package cn.mazexal.tools;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @Author: lujiao
 * @Date: 2022/3/21 10:26
 */
public class DateUtil {
    public static final String MinTime = "T00:00:00";
    public static final String MaxTime = "T23:59:59.999999999";
    public final static DateTimeFormatter FULL_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public final static String FULL_DATE_FORMAT_STR = "yyyy-MM-dd HH:mm:ss";
    public final static String DATE_NORMAL_FORMAT_STR = "yyyy-MM-dd";
    public final static String SIMPLE_FORMAT = "MM.dd";
    public final static Integer WEEK_OF_MILLION = 7 * 60 * 60 * 24 * 1000;
    public final static Integer DAY_OF_MILLION = 60 * 60 * 24 * 1000;
    public final static Integer HOUR_OF_MILLION = 60 * 60 * 1000;
    public final static Integer MINUTE_OF_MILLION = 60 * 1000;
    private final static String DATE_SIMPLE_FORMAT = "yyyyMMdd";

    /**
     * 获取本周的第一天00:00:00
     *
     * @return String
     **/
    public static long getWeekStart() {
        return getWeekStart(new Date());
    }

    public static long getWeekStart(Date date) {
        LocalDate today = dateToLocalDate(date);
        DayOfWeek dow = today.getDayOfWeek();
        int todayValue = dow.getValue();
        int monday = DayOfWeek.MONDAY.getValue();

        int diff = todayValue - monday;
        LocalDate day = today.minusDays(diff);
        LocalDateTime ldt = LocalDateTime.of(day.getYear(), day.getMonth(), day.getDayOfMonth(), 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    /**
     * 获取本周的最后一天23:59:59
     *
     * @return String
     **/
    public static long getWeekEnd() {
        return getWeekEnd(new Date());
    }

    public static long getWeekEnd(Date date) {
        LocalDate today = dateToLocalDate(date);
        DayOfWeek dow = today.getDayOfWeek();
        int todayValue = dow.getValue();
        int sunday = DayOfWeek.SUNDAY.getValue();
        int diff = sunday - todayValue;
        LocalDate day = today.plusDays(diff);
        LocalDateTime ldt = LocalDateTime.of(day.getYear(), day.getMonth(), day.getDayOfMonth(), 23, 59, 59);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli() + 999;
    }

    /**
     * 获取本月第一天
     *
     * @param date
     * @return
     */
    public static long getMonthStart(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDateTime ldt = LocalDateTime.of(today.getYear(), today.getMonth(), 1, 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    /**
     * 获取本月最后一天
     *
     * @param date
     * @return
     */
    public static long getMonthEnd(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
        LocalDateTime ldt = LocalDateTime.of(lastDay.getYear(), lastDay.getMonth(), lastDay.getDayOfMonth(), 23, 59, 59);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli() + 999;
    }

    /**
     * 获取上月第一天
     *
     * @param date
     * @return
     */
    public static long getLastMonthStart(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusMonths(1);
        LocalDateTime ldt = LocalDateTime.of(last.getYear(), last.getMonth(), 1, 0, 0, 0);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli();
    }

    /**
     * 获取上月最后一天
     *
     * @param date
     * @return
     */
    public static long getLastMonthEnd(Date date) {
        LocalDate today = dateToLocalDate(date);
        LocalDate last = today.minusMonths(1);
        LocalDate lastDay = last.with(TemporalAdjusters.lastDayOfMonth());
        LocalDateTime ldt = LocalDateTime.of(lastDay.getYear(), lastDay.getMonth(), lastDay.getDayOfMonth(), 23, 59, 59);
        ZonedDateTime zdt = ldt.atZone(ZoneId.of(ZoneId.systemDefault().getId()));
        return zdt.toInstant().toEpochMilli() + 999;
    }

    public static long getWeekStartTimeStamp() {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int value = dayOfWeek.getValue();
        LocalDate localDate = now.minusDays(value - 1);
        LocalDateTime parse = LocalDateTime.parse(localDate.toString() + MinTime);
        Instant instant = parse.atZone(ZoneId.systemDefault()).toInstant();
        return instant.toEpochMilli();
    }

    public static long getWeekEndTimeStamp() {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int value = dayOfWeek.getValue();
        LocalDate localDate = now.plusDays(7 - value);
        LocalDateTime parse = LocalDateTime.parse(localDate.toString() + MaxTime);
        Instant instant = parse.atZone(ZoneId.systemDefault()).toInstant();
        return instant.toEpochMilli();
    }

    public static long getLastWeekStartTimeStamp() {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int value = dayOfWeek.getValue();
        LocalDate localDate = now.minusDays(value - 1);
        LocalDate last = localDate.minusWeeks(1);
        LocalDateTime parse = LocalDateTime.parse(last.toString() + MinTime);
        Instant instant = parse.atZone(ZoneId.systemDefault()).toInstant();
        return instant.toEpochMilli();
    }

    public static long getLastWeekEndTimeStamp() {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int value = dayOfWeek.getValue();
        LocalDate localDate = now.plusDays(7 - value);
        LocalDate last = localDate.minusWeeks(1);
        LocalDateTime parse = LocalDateTime.parse(last.toString() + MaxTime);
        Instant instant = parse.atZone(ZoneId.systemDefault()).toInstant();
        return instant.toEpochMilli();
    }

    public static long getWeekStartTimeStamp(Long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
        LocalDate date = localDateTime.toLocalDate();
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        int value = dayOfWeek.getValue();
        LocalDate localDate = date.minusDays(value - 1);
        LocalDateTime parse = LocalDateTime.parse(localDate.toString() + MinTime);
        return parse.atZone(zoneId).toInstant().toEpochMilli();
    }

    public static long getWeekEndTimeStamp(Long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
        LocalDate date = localDateTime.toLocalDate();
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        int value = dayOfWeek.getValue();
        LocalDate localDate = date.plusDays(7 - value);
        LocalDateTime parse = LocalDateTime.parse(localDate.toString() + MaxTime);
        return parse.atZone(zoneId).toInstant().toEpochMilli();
    }

    /**
     * 获取yyyyMMdd的数据
     *
     * @param date
     * @return
     */
    public static Integer getIntDate(Date date) {
        DateFormat dateFormat = new SimpleDateFormat(DATE_SIMPLE_FORMAT);
        return Integer.valueOf(dateFormat.format(date));
    }

    public static Integer getIntDate(Long date) {
        return getIntDate(new Date(date));
    }

    public static Integer getIntDate() {
        return getIntDate(new Date());
    }

    /**
     * 获取一天开始时间戳
     *
     * @param date
     * @return
     */
    public static Long getDayBegin(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        return getDayBegin(localDate);
    }

    /**
     * 获取一天开始时间戳
     *
     * @param localDate
     * @return
     */
    public static Long getDayBegin(LocalDate localDate) {
        LocalDateTime localDateTime = LocalDateTime.of(localDate.getYear(),
                localDate.getMonth(), localDate.getDayOfMonth(), 0, 0, 0);
        return toEpochMilli(localDateTime);
    }

    /**
     * 获取一天开始时间戳
     *
     * @return
     */
    public static Long getDayBegin() {
        return getDayBegin(new Date());
    }

    /**
     * 获取一天结束时间戳
     *
     * @param end
     * @return
     */
    public static Long getDayEnd(Date end) {
        return getDayBegin(end) + DAY_OF_MILLION - 1;
    }

    public static Long getDayEnd() {
        return getDayEnd(new Date());
    }

    /**
     * 获取一天结束时间戳
     *
     * @param end
     * @return
     */
    public static Long getDayEnd(LocalDate end) {
        return getDayBegin(end) + DAY_OF_MILLION - 1;
    }

    /**
     * 日期转LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate dateToLocalDate(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 转时间戳
     *
     * @param time
     * @return
     */
    public static long toEpochMilli(LocalDateTime time) {
        return time.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * 字符串转LocalDateTime
     *
     * @param str yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static LocalDateTime toLocalDateTime(String str) {
        return LocalDateTime.parse(str, FULL_DATE_FORMAT);
    }

    public static String toFullTime(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static String toFullTime(LocalDateTime date) {
        return date.format(FULL_DATE_FORMAT);
    }

    public static String toFullTime(long millis) {
        Date date = new Date();
        date.setTime(millis);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    /**
     * yyyy-MM-dd HH:mm
     *
     * @param millis
     * @return
     */
    public static String toYearMonthDayHourMinute(long millis) {
        Date date = new Date();
        date.setTime(millis);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        return sdf.format(date);
    }

    /**
     * 获得毫秒
     *
     * @param ldt
     * @return
     */
    public static long toMillisecond(LocalDateTime ldt) {
        ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
        return zdt.toInstant().toEpochMilli();
    }

    /**
     * 获取几天前的数据
     *
     * @param dayBefore 推移值
     * @param date      起始值
     * @return
     */
    public static Date getDateBefore(Date date, int dayBefore) {
        return new Date(date.getTime() - dayBefore * DAY_OF_MILLION);
    }

    /**
     * 获取昨天起始值
     *
     * @param date
     * @return
     */
    public static Date getYesterday(Date date) {
        return new Date(getDayBegin(date) - DAY_OF_MILLION);
    }

    /**
     * 将区间时间显示为天数
     *
     * @param expireTime
     * @return
     */
    public static String getDurationToStr(Long expireTime) {
        Long now = System.currentTimeMillis();
        Long duration = expireTime - now;
        if (duration <= 0) {
            return "已过期";
        } else {
            StringBuilder sb = new StringBuilder();
            Long days = duration / DAY_OF_MILLION;
            if (days > 0) {
                sb.append(days + "天");
            }
            Long left = duration % DAY_OF_MILLION;
            Long hours = left / HOUR_OF_MILLION;
            if (hours > 0) {
                sb.append(hours + "时");
            }
            left = duration % HOUR_OF_MILLION;
            Long minutes = left / MINUTE_OF_MILLION;
            if (minutes > 0) {
                sb.append(minutes + "分");
            }
            return sb.toString();
        }
    }

    public static Long getTimestamp(Long timestamp, Long type) {
        TimeZone chinaZone = TimeZone.getTimeZone("GMT+08:00");

        Calendar calendar = Calendar.getInstance(chinaZone);
        calendar.setTimeInMillis(timestamp);

        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        if (type.equals(4L)) {
            calendar.set(Calendar.MONTH, 0);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
        } else if (type.equals(3L)) {
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
        } else if (type.equals(2L)) {
            calendar.set(Calendar.HOUR_OF_DAY, 0);
        }

        return calendar.getTimeInMillis();
    }

    /**
     * 转换成 LocalDate 对象
     *
     * @param yyyyMMdd 日期
     * @return
     */
    public static LocalDate toLocalDate(Long yyyyMMdd) {
        return toLocalDate(yyyyMMdd + "");
    }

    /**
     * 转换成 LocalDate 对象
     *
     * @param yyyyMMdd 日期
     * @return
     */
    public static LocalDate toLocalDate(String yyyyMMdd) {
        LocalDate date = null;
        try {
            date = LocalDate.parse(yyyyMMdd, DateTimeFormatter.BASIC_ISO_DATE);
        } catch (DateTimeException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 转换成数字型的日期
     *
     * @param date
     * @return yyyyMMdd
     */
    public static int toYearMonthDay(LocalDate date) {
        return Integer.parseInt(date.format(DateTimeFormatter.BASIC_ISO_DATE));
    }

    /**
     * 构建按照日期的分页
     *
     * @param beginTime
     * @param endTime
     * @param page
     * @param pageSize
     * @param count
     * @return
     */
    public static List<Long> buildDayList(Long beginTime, Long endTime, Integer page, Integer pageSize, Long count) {
        List<Long> res = new ArrayList<>(count.intValue());
        Long endDayBegin = DateUtil.getDayBegin(new Date(endTime));
        while (beginTime <= endDayBegin) {
            res.add(beginTime);
            beginTime = beginTime + DAY_OF_MILLION;
        }
        return pageBySubList(res, page, pageSize);
    }

    /**
     * 分页工具
     *
     * @param list
     * @param page
     * @param pageSize
     * @return
     */
    public static List pageBySubList(List list, int page, int pageSize) {

        int totalCount = list.size();

        int pagecount = 0;

        List subList;

        int m = totalCount % pageSize;

        if (m > 0) {

            pagecount = totalCount / pageSize + 1;

        } else {

            pagecount = totalCount / pageSize;

        }

        if (m == 0) {

            subList = list.subList((page - 1) * pageSize, pageSize * (page));

        } else {

            if (page == pagecount) {

                subList = list.subList((page - 1) * pageSize, totalCount);

            } else {

                subList = list.subList((page - 1) * pageSize, pageSize * (page));

            }

        }

        return subList;

    }

    /**
     * 格式化日期输出
     *
     * @param dayBegin
     * @param dateNormalFormatStr
     * @return
     */
    public static String formatDate(Long dayBegin, String dateNormalFormatStr) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateNormalFormatStr);
        return sdf.format(new Date(dayBegin));
    }

    public static String formatDate(Long input) {
        return formatDate(input, FULL_DATE_FORMAT_STR);
    }


    /**
     * 获取时间移除分钟秒毫秒
     *
     * @return
     */
    public static Long getCurrentHour() {
        TimeZone chinaZone = TimeZone.getTimeZone("GMT+08:00");
        Calendar calendar = Calendar.getInstance(chinaZone);
        calendar.setTimeInMillis(System.currentTimeMillis());

        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }



    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static Long getTimeStamp(String dateStr) throws Exception {
        Date date = sdf.parse(dateStr);
        return date.getTime();
    }
}
